<!--
 * @description 选项卡组件
 * @author: 陈陈
 * @date: 2025/05/09
 * @phone: 18560000860
 * @email: 18560000860@qq.com
 * @company: 济南晨霜信息技术有限公司 /
 * @business: 承接前后端项目的开发
-->
<template>
	<view
		class="pure-tabs"
		:class="_classes"
		:style="_styles"
	>
		<!-- Left -->
		<view
			class="pure-tabs__left"
			v-if="$slots.left"
		>
			<slot name="left"></slot>
		</view>

		<!-- Content -->
		<view class="pure-tabs__content">
			<scroll-view
				class="pure-tabs__scroll-view pure-hide-scrollbar"
				:scroll-x="disabled ? false : _isScrollX"
				:scroll-y="disabled ? false : _isScrollY"
				:scroll-left="_scrollLeft"
				:scroll-top="_scrollTop"
				:scroll-with-animation="animation"
				@scroll="_onScroll"
			>
				<view class="pure-tabs__items">
					<view
						class="pure-tabs__item"
						v-for="(item, index) in list"
						:key="index"
						:class="{
							'pure-tabs__item--active': index === current,
							'pure-tabs__item--disabled': item?.disabled
						}"
						@tap="_onTabClick(index, item)"
						:hover-class="hoverClass"
					>
						<text class="pure-tabs__item__text">{{ item?.[labelKey] }}</text>
						<view class="pure-tabs__item__indicator">
							<slot
								name="indicator"
								:item="item"
								:activated="index === current"
								:index="index"
							></slot>
						</view>
					</view>
					<view
						class="pure-tabs__bar"
						v-if="showBar"
						:style="vertical ? { top: _barTop + 'px' } : { left: _barLeft + 'px' }"
					>
						<slot name="bar">
							<view class="pure-tabs__bar__line"></view>
						</slot>
					</view>
				</view>
			</scroll-view>
		</view>

		<!-- Right -->
		<view
			class="pure-tabs__right"
			v-if="$slots.right"
		>
			<slot name="right"></slot>
		</view>
	</view>
</template>

<script>
	import commonComponentOptions from "../../config/options";
	export default {
		options: commonComponentOptions
	};
</script>

<script setup>
	import { ref, computed, onMounted, getCurrentInstance, nextTick, watchEffect } from "vue";
	import props from "./props";
	import { getRect, delay } from "@/uni_modules/pure-utils";
	import { getThemeValue } from "../../utils";

	// -------------------------------------------------------------------------------- Refs
	// 组件实例
	const _instance = getCurrentInstance();

	// 滚动位置
	const _scrollLeft = ref(0);
	const _scrollTop = ref(0);

	// 是否滚动中
	let _scrolling = null;

	// 指示条的位置
	const _barLeft = ref(null);
	const _barTop = ref(null);

	// -------------------------------------------------------------------------------- Props
	const _props = defineProps(props);

	// -------------------------------------------------------------------------------- Emits
	const _emits = defineEmits(["onClick"]);

	// -------------------------------------------------------------------------------- Classes
	const _classes = computed(() => {
		const array = [];

		// 滚动方向
		if (_isScrollX.value) array.push("pure-tabs--scroll-x");
		if (_isScrollY.value) array.push("pure-tabs--scroll-y");

		// 禁止滚动
		if (_props.disabled) array.push("pure-tabs--disabled");

		// 等分布局
		if (_props.equal) array.push("pure-tabs--equal");

		// 两端对齐布局
		if (_props.justify) array.push("pure-tabs--justify");

		// 主题
		if (_props.theme) array.push(`pure-tabs--theme pure-tabs--theme-${_props.theme}`);

		// 幽灵样式
		if (_props.ghost) array.push("pure-tabs--ghost");

		// 镂空样式
		if (_props.plain) array.push("pure-tabs--plain");

		return array;
	});

	// -------------------------------------------------------------------------------- Styles
	const _styles = computed(() => {
		const array = [];

		// 主题
		if (_props.theme) array.push(`--pure-tabs-theme: ${getThemeValue(_props.theme)};`);

		// 激活项字体加粗
		if (_props.bold) array.push(`--pure-tabs-item-active-font-weight: ${_props.bold};`);

		return array;
	});

	// 监听影响重新布局的数据
	watchEffect(() => {
		// 解构数组，不使用变量名，仅为触发依赖收集
		[_props.list, _props.vertical, _props.current];

		// 重新布局
		_calcLayout();
	});

	// 是否横向滚动
	const _isScrollX = computed(() => {
		// 设置为纵向滚动
		if (_props.vertical) return false;
		return true;
	});

	// 是否纵向滚动
	const _isScrollY = computed(() => {
		// 纵向滚动开启状态
		return _props.vertical;
	});

	// 组件渲染完成后布局一次
	onMounted(async () => {
		// 计算布局
		_calcLayout();
	});

	// 计算布局
	async function _calcLayout() {
		// 等待数据渲染完成
		await nextTick();
		await delay(50);

		// 获取滚动容器的布局信息
		const scrollViewRect = await getRect(".pure-tabs__scroll-view", _instance.proxy);

		// 未成功获取到滚动容器的布局信息
		if (!scrollViewRect) return console.warn("未获取到 Pure Tabs 滚动容器的布局信息。");

		// 获取列表容器的布局信息
		const listRect = await getRect(".pure-tabs__items", _instance.proxy);

		// 未成功获取到列表容器的布局信息
		if (!listRect) return console.warn("未获取到 Pure Tabs 列表容器的布局信息。");

		// 获取当前激活项的布局信息
		const activeItemRect = await getRect(".pure-tabs__item--active", _instance.proxy);

		// 未成功获取到当前激活项的布局信息
		if (!activeItemRect) return console.warn("未获取到 Pure Tabs 当前激活项的布局信息。");

		// 吸附贴边模式
		if (_props.sticky) {
			// 滚动到容器左侧
			_scrollToLeft(scrollViewRect, listRect, activeItemRect);
			return;
		}

		// 只将激活项滚动到可视区域模式
		if (_props.visible) {
			// 滚动到可视区域,即激活项右侧和容器右侧对齐
			_scrollToVisible(scrollViewRect, listRect, activeItemRect);
			return;
		}

		// 默认滚动到居中
		_scrollToCenter(scrollViewRect, listRect, activeItemRect);
	}

	// 滚动到居中
	function _scrollToCenter(scrollViewRect, listRect, activeItemRect) {
		// 横向滚动
		if (!_props.vertical) {
			// 滚动容器的布局信息
			const { width: scrollViewWidth } = scrollViewRect;

			//  列表容器的布局信息
			const { left: listLeft } = listRect;

			// 当前子元素的布局信息
			const { width: itemWidth, left: itemLeft } = activeItemRect;

			// 中间点
			const centerPoint = scrollViewWidth / 2;

			// 应该滚动到的位置
			const scrollTo = itemLeft - listLeft - centerPoint + itemWidth / 2;

			// 滚动
			_scrollLeft.value = scrollTo;

			// 指示条的位置
			_barLeft.value = itemLeft - listLeft + itemWidth / 2;

			return;
		}

		// 纵向滚动
		// 滚动容器的布局信息
		const { height: scrollViewHeight } = scrollViewRect;

		//  列表容器的布局信息
		const { top: listTop } = listRect;

		// 当前子元素的布局信息
		const { height: itemHeight, top: itemTop } = activeItemRect;

		// 中间点
		const centerPoint = scrollViewHeight / 2;

		// 应该滚动到的位置
		const scrollTo = itemTop - listTop - centerPoint + itemHeight / 2;

		// 滚动
		_scrollTop.value = scrollTo;

		// 指示条的位置
		_barTop.value = itemTop - listTop + itemHeight / 2;
	}

	// 滚动到容器最左侧
	function _scrollToLeft(scrollViewRect, listRect, activeItemRect) {
		// 横向滚动
		if (!_props.vertical) {
			//  列表容器的布局信息
			const { left: listLeft } = listRect;

			// 当前子元素的布局信息
			const { width: itemWidth, left: itemLeft } = activeItemRect;

			// 应该滚动到的位置
			const scrollTo = itemLeft - listLeft;

			// 滚动
			_scrollLeft.value = scrollTo;

			// 指示条的位置
			_barLeft.value = itemLeft - listLeft + itemWidth / 2;

			return;
		}

		// 纵向滚动
		//  列表容器的布局信息
		const { top: listTop } = listRect;

		// 当前子元素的布局信息
		const { height: itemHeight, top: itemTop } = activeItemRect;

		// 应该滚动到的位置
		const scrollTo = itemTop - listTop;

		// 滚动
		_scrollTop.value = scrollTo;

		// 指示条的位置
		_barTop.value = itemTop - listTop + itemHeight / 2;
	}

	// 滚动到可视区域,即激活项右侧和容器右侧对齐
	function _scrollToVisible(scrollViewRect, listRect, activeItemRect) {
		// 横向滚动
		if (!_props.vertical) {
			// 滚动容器的布局信息
			const { width: scrollViewWidth, left: scrollViewLeft, right: scrollViewRight } = scrollViewRect;

			//  列表容器的布局信息
			const { left: listLeft } = listRect;

			// 当前子元素的布局信息
			const { width: itemWidth, left: itemLeft, right: itemRight } = activeItemRect;

			// 先判断右侧是否不可见
			if (itemRight > scrollViewRight) {
				// 应该滚动到的位置
				const scrollTo = itemLeft - listLeft - scrollViewWidth + itemWidth;

				// 滚动
				_scrollLeft.value = scrollTo;
			}

			// 在判断左侧是否不可见
			else if (itemLeft < scrollViewLeft) {
				// 应该滚动到的位置
				const scrollTo = itemLeft - listLeft;

				// 滚动
				_scrollLeft.value = scrollTo;
			}

			// 指示条的位置
			_barLeft.value = itemLeft - listLeft + itemWidth / 2;

			return;
		}

		// 纵向滚动
		// 滚动容器的布局信息
		const { height: scrollViewHeight, top: scrollViewTop, bottom: scrollViewBottom } = scrollViewRect;

		//  列表容器的布局信息
		const { top: listTop } = listRect;

		// 当前子元素的布局信息
		const { height: itemHeight, top: itemTop, bottom: itemBottom } = activeItemRect;

		// 先判断底部是否不可见
		if (itemBottom > scrollViewBottom) {
			// 应该滚动到的位置
			const scrollTo = itemTop - listTop - scrollViewHeight + itemHeight;

			// 滚动
			_scrollTop.value = scrollTo;
		}

		// 再判断顶部是否不可见
		else if (itemTop < scrollViewTop) {
			// 应该滚动到的位置
			const scrollTo = itemTop - listTop;

			// 滚动
			_scrollTop.value = scrollTo;
		}

		// 指示条的位置
		_barTop.value = itemTop - listTop + itemHeight / 2;
	}

	// 滚动事件
	function _onScroll() {
		// 滚动状态为正在滚动
		if (_scrolling) {
			clearTimeout(_scrolling);
			_scrolling = null;
		}

		// 设置新的定时器
		_scrolling = setTimeout(() => {
			clearTimeout(_scrolling);
			_scrolling = null;
		}, 100);
	}

	// 子项点击事件
	function _onTabClick(index, item) {
		// 正在滚动中
		if (_scrolling !== null) return;

		// 禁用状态
		if (item.disabled) return;

		// 触发事件
		_emits("onClick", index, item);
	}
</script>

<style scoped lang="scss">
	@import "./style.scss";
</style>
